//******************************************************************
//******************************************************************
//**********          ANts Peer To Peer Sources        *************
//
// ANts P2P realizes a third generation P2P net. It protects your
// privacy while you are connected and makes you not trackable, hiding
// your identity (ip) and crypting everything you are sending/receiving
// from others.

// Copyright (C) 2004  Roberto Rossi

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

package ants.p2p.query;

import java.util.*;
import java.io.*;
import java.net.*;
import javax.crypto.*;

import ants.p2p.*;
import ants.p2p.filesharing.*;
import ants.p2p.gui.*;
import ants.p2p.utils.indexer.*;
import ants.p2p.utils.encoding.*;
import ants.p2p.utils.addresses.*;
import ants.p2p.query.security.*;

import org.apache.log4j.*;

public class QueryManager {
  public static int resultSize = 50;
  static int maxLocalResultsToReturn = 50;
  static int maxRemoteResultsToReturn = 50;

  static Logger _logger = Logger.getLogger(QueryManager.class.getName());

  WarriorAnt caller;
  QueryMessage queryMessage;
  public ArrayList resultSet = new ArrayList();

  private boolean onlyRemote;

  public QueryManager(QueryNode query, WarriorAnt caller) throws Exception{
    if(query instanceof QueryHttpServerItem){
      this.resultSet = new ArrayList();
      Enumeration keys = BackgroundEngine.getInstance().getHttpServersList().keys();
      while (keys.hasMoreElements()) {
        String httpServer = (String) keys.nextElement();
        HttpServerInfo curSI = (HttpServerInfo) BackgroundEngine.getInstance().getHttpServersList().get(httpServer);
        this.resultSet.add(curSI);
      }
    }else{
      onlyRemote = true;
      this.caller = caller;
      this.resultSet = this.process(query);
      ArrayList processedResultSet = new ArrayList();
      if (this.resultSet != null) {
        for (int x = 0; x < resultSet.size(); x++) {
          BackgroundEngine be = BackgroundEngine.getInstance();
          RemoteFileInfos rfi = (RemoteFileInfos) be.remoteFilesIndexHash.get( (
              String) resultSet.get(x));
          if (rfi != null &&
              rfi.hasSources(BackgroundEngine.remoteIndexedDocumentsTimeout)) {
            Enumeration sources = rfi.getOwners().keys();
            while (sources.hasMoreElements()) {
              String curSource = (String) sources.nextElement();
              Long lastTimeSeen = (Long) rfi.getOwners().get(curSource);
              QueryRemoteFileTuple qpt = new QueryRemoteFileTuple(
                  null,
                  rfi.getName(), rfi.getHash(), rfi.getED2KFileHash(),
                  new Long(rfi.getSize()), curSource,
                  caller.getLocalInetAddress(),
                  rfi.getExtendedInfos(), lastTimeSeen);
              processedResultSet.add(qpt);
            }
          }
        }
        this.resultSet = processedResultSet;
      }
      else {
        this.resultSet = new ArrayList();
      }
    }
  }

  public QueryManager(QueryMessage queryMessage, WarriorAnt caller) throws Exception{
    this.onlyRemote = false;
    this.caller=caller;
    this.queryMessage = queryMessage;
    if(this.queryMessage.tuples.size() < QueryManager.resultSize){
      this.resultSet = this.process(queryMessage.query);
      queryMessage.getPublicHeader().generateSessionKey();
      if (this.queryMessage.getQuery() instanceof QuerySupernodeItem) {
        AsymmetricProvider ap = new AsymmetricProvider(false);
        QueryMessage qm = new QueryMessage(new QueryFileListItem(null), ap.getPublicHeader());
        if (WarriorAnt.isSupernode()) {
          QuerySupernodeTuple qt = new QuerySupernodeTuple(queryMessage.
              getPublicHeader().getEncryptedSessionKey(),
              new Long(System.currentTimeMillis()),
              new Long(BackgroundEngine.getInstance().getTotalRemoteSharedSize() +
                       BackgroundEngine.getInstance().getTotalLocalSharedSize()),
               qm, this.caller.getIdent(), this.caller.getLocalInetAddress());
          qt.encrypt(queryMessage.getPublicHeader().getEncCipher());
          queryMessage.tuples.add(qt);
        }
        Enumeration keys = BackgroundEngine.getInstance().getSupernodeList().keys();
        int counter = 0;
        while (keys.hasMoreElements() && ((WarriorAnt.isSupernode() && counter++ < 5) || counter++ < 3)) {
          String superNode = (String) keys.nextElement();
          QuerySupernodeTuple curQueryTuple = (QuerySupernodeTuple)
              BackgroundEngine.getInstance().getSupernodeList().get(superNode);
          QuerySupernodeTuple qst = new QuerySupernodeTuple(queryMessage.
              getPublicHeader().getEncryptedSessionKey(),
              curQueryTuple.getSeenOn(),
              curQueryTuple.getTotalShareDimension(),
                curQueryTuple.getQueryMessage(), curQueryTuple.getOwnerID(), curQueryTuple.getOwnerIP());
          qst.encrypt(queryMessage.getPublicHeader().getEncCipher());
          queryMessage.tuples.add(qst);
        }
        queryMessage.getPublicHeader().invalidateSessionKey();
      }
      else if (this.queryMessage.getQuery() instanceof QueryInetAddressItem) {
        if (this.resultSet != null) {
          for (int x = 0; x < resultSet.size() && this.queryMessage.tuples.size() < QueryManager.resultSize; x++) {
            ServerInfo si = new ServerInfo(queryMessage.getPublicHeader().getEncryptedSessionKey(),
                                           FrameAnt.
                getInstance(null).getGuiAnt().getConnectionAntPanel().getLocalStringAddress(),
                                           new Integer(caller.getServerPort()),
                                           WarriorAnt.ConnectionType);
            si.encrypt(queryMessage.getPublicHeader().getEncCipher());
            queryMessage.tuples.add(si);
            /*ArrayList furtherPeers = InetAddressEngine.getInstance().getPeersWithFreeSlots();
            for(int k = 0; k < furtherPeers.size(); k++){
              ServerInfo fsi = new ServerInfo((ServerInfo)furtherPeers.get(k), queryMessage.getPublicHeader().getEncryptedSessionKey());
              fsi.encrypt(queryMessage.getPublicHeader().getEncCipher());
              queryMessage.tuples.add(fsi);
            }*/
          }
          queryMessage.getPublicHeader().invalidateSessionKey();
        }
      }
      else if (this.queryMessage.getQuery() instanceof QueryHttpServerItem) {
        if (this.resultSet != null) {
          for (int x = 0; x < resultSet.size() && this.queryMessage.tuples.size() < QueryManager.resultSize; x++) {
            HttpServerInfo si = new HttpServerInfo(queryMessage.getPublicHeader().getEncryptedSessionKey(),
                                           caller.getHttpServerHomePage(),
                                           caller.getHttpServerDescription(),
                                           caller.getIdent(), this.caller.getLocalInetAddress(), new Long(System.currentTimeMillis()));
            si.encrypt(queryMessage.getPublicHeader().getEncCipher());
            queryMessage.tuples.add(si);
          }
          Enumeration keys = BackgroundEngine.getInstance().getHttpServersList().keys();
          int counter = 0;
          while (keys.hasMoreElements() && ( (WarriorAnt.isSupernode() && counter++ < Integer.MAX_VALUE) || counter++ < 10)) {
            String httpServer = (String) keys.nextElement();
            HttpServerInfo curSI = (HttpServerInfo) BackgroundEngine.getInstance().getHttpServersList().get(httpServer);
            HttpServerInfo si = new HttpServerInfo(queryMessage.getPublicHeader().getEncryptedSessionKey(),
                curSI.getHomePage(),
                curSI.getDescription(),
                curSI.getOwnerId(), curSI.getOwnerIp(), curSI.getSeenOn());
            si.encrypt(queryMessage.getPublicHeader().getEncCipher());
            queryMessage.tuples.add(si);
          }
          queryMessage.getPublicHeader().invalidateSessionKey();
        }
      }
      else if (this.queryMessage.getQuery() instanceof QueryHashItem) {
        QueryHashItem qHashItem = (QueryHashItem)this.queryMessage.getQuery();
        if (this.resultSet != null) {
          if(resultSet.size() > 1 && resultSet.get(0).equals("CompleteFileHash") && resultSet.get(1) != null){
            QueryCompletedFileTuple qt = new QueryCompletedFileTuple(queryMessage.getPublicHeader().getEncryptedSessionKey(),
                (new File( (String) resultSet.get(1))).getName(),
                ( (FileInfos) BackgroundEngine.getInstance().
                 sharedFilesIndexName.get(resultSet.get(1))).getHash(),
                ( (FileInfos) BackgroundEngine.getInstance().
                 sharedFilesIndexName.get(resultSet.get(1))).getED2KHash(),
                qHashItem.getChunkHashes ? ( (FileInfos) BackgroundEngine.getInstance().
                 sharedFilesIndexName.get(resultSet.get(1))).getChunckHashes() : null,
                new Long( ( (FileInfos) BackgroundEngine.getInstance().
                           sharedFilesIndexName.get(resultSet.get(1))).getSize()),
                caller.getIdent(), caller.getLocalInetAddress(),
                new Integer(caller.maxPullRequestsToServe -
                            caller.inServiceFilePullRequests.size()),
                WarriorAnt.ConnectionType,
                ( (FileInfos) BackgroundEngine.getInstance().
                          sharedFilesIndexName.get(resultSet.get(1))).getExtendedInfos(),
                ( (FileInfos) BackgroundEngine.getInstance().
                          sharedFilesIndexName.get(resultSet.get(1))).getComment());
            qt.encrypt(queryMessage.getPublicHeader().getEncCipher());
            queryMessage.tuples.add(qt);
          }else if(resultSet.size() > 1 && resultSet.get(0).equals("PartialFileHash") && resultSet.get(1) != null){
            BackgroundEngine be = BackgroundEngine.getInstance();
            QueryPartialFileTuple qpt = be.getPartialFileTuple(queryMessage.getPublicHeader().getEncryptedSessionKey(),
                (String) resultSet.get(1), qHashItem.type,
                caller.getIdent(), new Integer(caller.maxPullRequestsToServe -
                                          caller.inServiceFilePullRequests.
                                          size()), WarriorAnt.ConnectionType, qHashItem.getChunkHashes);
            qpt.encrypt(queryMessage.getPublicHeader().getEncCipher());
            queryMessage.tuples.add(qpt);
          }else if(queryMessage.getType() == 0 && resultSet.size() > 1 && resultSet.get(0).equals("RemoteFileHash") && resultSet.get(1) != null){
            BackgroundEngine be = BackgroundEngine.getInstance();
            RemoteFileInfos rfi = be.getRemoteFile((String) resultSet.get(1), qHashItem.type);
            if(rfi != null && rfi.hasSources(BackgroundEngine.remoteIndexedDocumentsTimeout)){
              Enumeration sources = rfi.getOwners().keys();
              while (sources.hasMoreElements()) {
                String curSource = (String) sources.nextElement();
                if(!curSource.equals(queryMessage.getSource())){
                  Long lastTimeSeen = (Long) rfi.getOwners().get(curSource);
                  QueryRemoteFileTuple qt = new QueryRemoteFileTuple(
                      queryMessage.
                      getPublicHeader().getEncryptedSessionKey(),
                      rfi.getName(), rfi.getHash(), rfi.getED2KFileHash(),
                      new Long(rfi.getSize()), curSource, caller.getLocalInetAddress(),
                      rfi.getExtendedInfos(), lastTimeSeen);
                  qt.encrypt(queryMessage.getPublicHeader().getEncCipher());
                  queryMessage.tuples.add(qt);
                }
              }
            }
          }
          queryMessage.getPublicHeader().invalidateSessionKey();
        }
      }
      else if (this.queryMessage.getQuery() instanceof QueryRandomItem) {
        if (this.resultSet != null) {
          for (int x = 0;
               x < resultSet.size(); x++) {
            if (resultSet.get(x) instanceof FileInfos) {
              FileInfos fi = (FileInfos) resultSet.get(x);
              QueryCompletedFileTuple qt = new QueryCompletedFileTuple(
                  queryMessage.getPublicHeader().getEncryptedSessionKey(),
                  (new File(fi.getName())).getName(),
                  fi.getHash(),
                  fi.getED2KHash(),
                  null,
                  new Long(fi.getSize()),
                  caller.getIdent(), caller.getLocalInetAddress(),
                  new Integer(caller.maxPullRequestsToServe -
                              caller.inServiceFilePullRequests.size()),
                  WarriorAnt.ConnectionType,
                  fi.getExtendedInfos(),
                  fi.getComment());
              qt.encrypt(queryMessage.getPublicHeader().getEncCipher());
              queryMessage.tuples.add(qt);
            }else if(resultSet.get(x) instanceof StringHash){
              BackgroundEngine be = BackgroundEngine.getInstance();
              QueryPartialFileTuple qpt = be.getPartialFileTuple(queryMessage.getPublicHeader().getEncryptedSessionKey(),
                  ((StringHash) resultSet.get(x)).getHash(), QueryHashItem.ANTS_HASH,
                  caller.getIdent(), new Integer(caller.maxPullRequestsToServe -
                                            caller.inServiceFilePullRequests.
                                            size()),
                                      WarriorAnt.ConnectionType, false);
              qpt.encrypt(queryMessage.getPublicHeader().getEncCipher());
              queryMessage.tuples.add(qpt);
            }
            else if (resultSet.get(x) == null && resultSet.size() > x + 1) {
              x++;
              for (int y = x; y < resultSet.size(); y++, x++) {
                RemoteFileInfos rfi = (RemoteFileInfos) resultSet.get(y);
                if(rfi != null && rfi.hasSources(BackgroundEngine.remoteIndexedDocumentsTimeout)){
                  Enumeration sources = rfi.getOwners().keys();
                  while (sources.hasMoreElements()) {
                    String curSource = (String) sources.nextElement();
                    if(!curSource.equals(queryMessage.getSource())){
                      Long lastTimeSeen = (Long) rfi.getOwners().get(curSource);
                      QueryRemoteFileTuple qpt = new QueryRemoteFileTuple(
                          queryMessage.getPublicHeader().getEncryptedSessionKey(),
                          rfi.getName(), rfi.getHash(), rfi.getED2KFileHash(),
                          new Long(rfi.getSize()),
                          curSource, caller.getLocalInetAddress(),
                          rfi.getExtendedInfos(), lastTimeSeen);
                      qpt.encrypt(queryMessage.getPublicHeader().getEncCipher());
                      queryMessage.tuples.add(qpt);
                    }
                  }
                }
              }
            }
          }
          queryMessage.getPublicHeader().invalidateSessionKey();
        }
      }
      else{
        if (this.resultSet != null) {
          for (int x = 0; x < resultSet.size() && queryMessage.tuples.size() < QueryManager.resultSize; x++) {
            if(resultSet.get(x) instanceof String){
              QueryCompletedFileTuple qt = new QueryCompletedFileTuple(
                  queryMessage.getPublicHeader().getEncryptedSessionKey(),
                  (new File( (String) resultSet.get(x))).getName(),
                  ( (FileInfos) BackgroundEngine.getInstance().
                            sharedFilesIndexName.get(resultSet.get(x))).getHash(),
                  ( (FileInfos) BackgroundEngine.getInstance().
                            sharedFilesIndexName.get(resultSet.get(x))).getED2KHash(),
                  null,
                  new Long( ( (FileInfos) BackgroundEngine.getInstance().
                             sharedFilesIndexName.get(resultSet.get(x))).getSize()),
                  caller.getIdent(), caller.getLocalInetAddress(),
                  new Integer(caller.maxPullRequestsToServe -
                              caller.inServiceFilePullRequests.size()),
                  WarriorAnt.ConnectionType,
                  ( (FileInfos) BackgroundEngine.getInstance().
                            sharedFilesIndexName.get(resultSet.get(x))).getExtendedInfos(),
                  ( (FileInfos) BackgroundEngine.getInstance().
                            sharedFilesIndexName.get(resultSet.get(x))).getComment());
              qt.encrypt(queryMessage.getPublicHeader().getEncCipher());
              queryMessage.tuples.add(qt);
            }else if(resultSet.get(x) instanceof StringHash){
              BackgroundEngine be = BackgroundEngine.getInstance();
              QueryPartialFileTuple qpt = be.getPartialFileTuple(queryMessage.getPublicHeader().getEncryptedSessionKey(),
                  ((StringHash) resultSet.get(x)).getHash(), QueryHashItem.ANTS_HASH,
                  caller.getIdent(), new Integer(caller.maxPullRequestsToServe -
                                            caller.inServiceFilePullRequests.
                                            size()), WarriorAnt.ConnectionType, false);
              qpt.encrypt(queryMessage.getPublicHeader().getEncCipher());
              queryMessage.tuples.add(qpt);
            }else if(resultSet.get(x) == null && resultSet.size() > x + 1){
              x++;
              for (int y = x; y < resultSet.size() && this.queryMessage.tuples.size() < QueryManager.resultSize; y++, x++) {
                BackgroundEngine be = BackgroundEngine.getInstance();
                RemoteFileInfos rfi = (RemoteFileInfos) be.remoteFilesIndexHash.
                    get( (String) resultSet.get(y));
                if(rfi != null && rfi.hasSources(BackgroundEngine.remoteIndexedDocumentsTimeout)){
                  Enumeration sources = rfi.getOwners().keys();
                  while (sources.hasMoreElements()) {
                    String curSource = (String) sources.nextElement();
                    if(!curSource.equals(queryMessage.getSource())){
                      Long lastTimeSeen = (Long) rfi.getOwners().get(curSource);
                      QueryRemoteFileTuple qpt = new QueryRemoteFileTuple(
                          queryMessage.getPublicHeader().getEncryptedSessionKey(),
                          rfi.getName(), rfi.getHash(), rfi.getED2KFileHash(),
                          new Long(rfi.getSize()),
                          curSource, caller.getLocalInetAddress(),
                          rfi.getExtendedInfos(), lastTimeSeen);
                      qpt.encrypt(queryMessage.getPublicHeader().getEncCipher());
                      queryMessage.tuples.add(qpt);
                    }
                  }
                }
              }
            }
          }
          queryMessage.getPublicHeader().invalidateSessionKey();
        }
      }
    }
  }

  public QueryManager(WarriorAnt caller, QueryMessage queryMessage) throws Exception{
    this.caller=caller;
    AsymmetricProvider ap = new AsymmetricProvider(false);
    this.queryMessage = queryMessage;
    ArrayList decryptedRs = new ArrayList();
    this.resultSet=queryMessage.getTuples();
    if(this.queryMessage.getQuery() instanceof QuerySupernodeItem){
      if (this.resultSet != null) {
        Cipher decCipher = null;
        for (int x = 0; x < resultSet.size(); x++) {
          QuerySupernodeTuple qst = (QuerySupernodeTuple) resultSet.get(x);
          if (decCipher == null) {
            decCipher = ap.getDecCipher(qst.getEncryptedSessionKey());
          }
          qst.decrypt(decCipher);
          decryptedRs.add(qst);
        }
      }
      this.resultSet = decryptedRs;
    }
    else if(this.queryMessage.getQuery() instanceof QueryHttpServerItem){
      if (this.resultSet != null) {
        Cipher decCipher = null;
        for (int x = 0; x < resultSet.size(); x++) {
          HttpServerInfo si = (HttpServerInfo) resultSet.get(x);
          if(decCipher == null){
            decCipher = ap.getDecCipher(si.getEncryptedSessionKey());
          }
          si.decrypt(decCipher);
          if(!si.getOwnerId().equals(this.caller.getIdent()))
            decryptedRs.add(si);
        }
      }
      this.resultSet = decryptedRs;
    }
    else if(this.queryMessage.getQuery() instanceof QueryInetAddressItem){
      if (this.resultSet != null) {
        Cipher decCipher = null;
        for (int x = 0; x < resultSet.size(); x++) {
          ServerInfo si = (ServerInfo) resultSet.get(x);
          if(decCipher == null){
            decCipher = ap.getDecCipher(si.getEncryptedSessionKey());
          }
          si.decrypt(decCipher);
          si.sessionKey = "";
          decryptedRs.add(si);
        }
      }
      this.resultSet = decryptedRs;
    }
    else{
      if (this.resultSet != null) {
        Cipher decCipher = null;
        for (int x = 0; x < resultSet.size(); x++) {
          if(resultSet.get(x) instanceof QueryCompletedFileTuple){
            QueryCompletedFileTuple qft = (QueryCompletedFileTuple) resultSet.get(x);
            if (decCipher == null) {
              decCipher = ap.getDecCipher(qft.getEncryptedSessionKey());
            }
            qft.decrypt(decCipher);
            if(qft.checkHashesValidity())
              decryptedRs.add(qft);
          }else if(resultSet.get(x) instanceof QueryPartialFileTuple){
            QueryPartialFileTuple qpft = (QueryPartialFileTuple) resultSet.get(x);
            if (decCipher == null) {
              decCipher = ap.getDecCipher(qpft.getEncryptedSessionKey());
            }
            qpft.decrypt(decCipher);
            if(qpft.checkHashesValidity())
              decryptedRs.add(qpft);
          }else if(resultSet.get(x) instanceof QueryRemoteFileTuple){
            QueryRemoteFileTuple qrft = (QueryRemoteFileTuple) resultSet.get(x);
            if (decCipher == null) {
              decCipher = ap.getDecCipher(qrft.getEncryptedSessionKey());
            }
            qrft.decrypt(decCipher);
            if(!qrft.getOwnerID().equals(this.caller.getIdent()) && qrft.checkHashesValidity())
              decryptedRs.add(qrft);
          }else if(resultSet.get(x) instanceof HttpServerInfo){
            HttpServerInfo si = (HttpServerInfo) resultSet.get(x);
            if (decCipher == null) {
              decCipher = ap.getDecCipher(si.getEncryptedSessionKey());
            }
            si.decrypt(decCipher);
            if(!si.getOwnerId().equals(this.caller.getIdent()))
              decryptedRs.add(si);
          }
        }
      }
      this.resultSet = decryptedRs;
    }
  }

  public QueryMessage getQueryMessage(){
    return this.queryMessage;
  }

  public ArrayList process(QueryNode qn){
    if(qn instanceof QueryItem)
      return process((QueryItem)qn);
    else
      return null;
  }

  public ArrayList process(QueryItem qn){
    if(qn instanceof QueryStringItem)
      return process((QueryStringItem)qn);
    else if(qn instanceof QueryHashItem)
      return process((QueryHashItem)qn);
    else if(qn instanceof QueryRandomItem)
      return process((QueryRandomItem)qn);
    else if(qn instanceof QueryInetAddressItem)
      return process((QueryInetAddressItem)qn);
    else if(qn instanceof QueryHttpServerItem)
      return process((QueryHttpServerItem)qn);
    else if(qn instanceof QueryFileListItem)
      return process((QueryFileListItem)qn);
    else
      return null;
  }

  public ArrayList process(QueryRandomItem qh){
    ArrayList elements = new ArrayList();
    BackgroundEngine be = BackgroundEngine.getInstance();
    if(be!=null){
      int remainingLocalSpace = QueryManager.maxLocalResultsToReturn;
      if(be.sharedFilesIndexName.size() <= remainingLocalSpace){
        elements = new ArrayList(be.sharedFilesIndexName.values());
      }else{
        int startIndex = (int)Math.floor(Math.random()*(be.sharedFilesIndexName.size() - remainingLocalSpace));
        elements = new ArrayList(be.sharedFilesIndexName.values());
        elements = new ArrayList(elements.subList(startIndex, startIndex + remainingLocalSpace));
      }
      remainingLocalSpace -= elements.size();
      ArrayList partialHashes = be.getPartialFilesHashes();
      if(partialHashes.size() <= remainingLocalSpace){
        elements.addAll(partialHashes);
      }else if(remainingLocalSpace > 0){
        int startIndex = (int)Math.floor(Math.random()*(partialHashes.size() - remainingLocalSpace));
        elements.addAll(partialHashes.subList(startIndex, startIndex + remainingLocalSpace));
      }
      elements.add(null);
      if(be.remoteFilesIndexHash.size() <= QueryManager.maxRemoteResultsToReturn){
        elements.addAll(new ArrayList(be.remoteFilesIndexHash.values()));
      }else{
        int startIndex = (int)Math.floor(Math.random()*(be.remoteFilesIndexHash.size() - QueryManager.maxRemoteResultsToReturn));
        elements.addAll((new ArrayList(be.remoteFilesIndexHash.values())).subList(startIndex, startIndex + QueryManager.maxRemoteResultsToReturn));
      }
    }
    return elements;
  }

  public ArrayList process(QueryStringItem qn){
    String itemLower = qn.item.toLowerCase();
    ArrayList elements = new ArrayList();
    BackgroundEngine be = BackgroundEngine.getInstance();
    if(be!=null){
      if(!this.onlyRemote){
        elements = be.search(itemLower, qn.content);
        elements.add(null);
      }
      elements.addAll(be.searchRemoteFiles(itemLower, onlyRemote));
      return elements;
    }
    return new ArrayList();
  }

  public ArrayList process(QueryFileListItem qfli){
    ArrayList elements = new ArrayList();
    BackgroundEngine be = BackgroundEngine.getInstance();
    if(be!=null){
      elements.addAll(be.getCompleteFileList());
      return elements;
    }
    return new ArrayList();
  }

  public ArrayList process(QueryHashItem qh){
    String hash = qh.hash;
    String type = qh.type;
    ArrayList elements = new ArrayList();
    BackgroundEngine be = BackgroundEngine.getInstance();
    if(be != null &&
       hash != null && type != null){
      if(type.equals(QueryHashItem.ANTS_HASH)){
        if (be.sharedFilesIndexHash.get(hash) != null && !onlyRemote) {
          FileInfos elemInfo = (FileInfos) be.sharedFilesIndexHash.get(hash);
          elements.add("CompleteFileHash");
          elements.add(elemInfo.getName());
        }
        else if (be.getPartialFile(hash, QueryHashItem.ANTS_HASH) != null && !onlyRemote) {
          Object partialFile = be.getPartialFile(hash, QueryHashItem.ANTS_HASH);
          elements.add("PartialFileHash");
          elements.add(hash);
        }
        else if (be.getRemoteFile(hash, QueryHashItem.ANTS_HASH) != null){
          RemoteFileInfos rfi = be.getRemoteFile(hash, QueryHashItem.ANTS_HASH);
          elements.add("RemoteFileHash");
          elements.add(hash);
        }
      }else if(type.equals(QueryHashItem.ED2K_HASH)){
        if (be.sharedFilesIndexED2KHash.get(hash) != null && !onlyRemote) {
          FileInfos elemInfo = (FileInfos) be.sharedFilesIndexED2KHash.get(hash);
          elements.add("CompleteFileHash");
          elements.add(elemInfo.getName());
        }
        else if (be.getPartialFile(hash, QueryHashItem.ED2K_HASH) != null && !onlyRemote) {
          Object partialFile = be.getPartialFile(hash, QueryHashItem.ED2K_HASH);
          elements.add("PartialFileHash");
          elements.add(hash);
        }
        else if(be.getRemoteFile(hash, QueryHashItem.ED2K_HASH) != null){
          RemoteFileInfos rfi = be.getRemoteFile(hash, QueryHashItem.ED2K_HASH);
          elements.add("RemoteFileHash");
          elements.add(hash);
        }
      }
    }
    return elements;
  }

  public ArrayList process(QueryInetAddressItem qh) {
    ServerInfo serverInfo;
    ArrayList elements = new ArrayList();
    if(caller.getNeighbours().size() < caller.maxNeighbours){
      try{
        elements.add(new Boolean(true));
      }catch(Exception e){_logger.error("",e);}
    }
    return elements;
  }

  public ArrayList process(QueryHttpServerItem qh) {
    ArrayList elements = new ArrayList();
    if(caller.isHttpEnabled()){
      try{
        elements.add(new Boolean(true));
      }catch(Exception e){_logger.error("",e);}
    }
    return elements;
  }
}
